package turritopsis

import (
    "bufio"
    "encoding/binary"
    "errors"
    "fmt"
    "io"
    "net"
    "os"
    "strings"
    "time"
)

// ExternalSDumboACS creates an ACSFunc that proxies to an external sDumbo service over TCP.
// addr format: "host:port". It sends a simple length-prefixed request: "SID\n" and
// expects a response stream: uint32 numItems, then for each item: uint32 len, followed by payload bytes.
func ExternalSDumboACS(addr string, dialTimeout time.Duration) ACSFunc {
    if dialTimeout <= 0 {
        dialTimeout = 5 * time.Second
    }
    return func(sid string, input []byte) ([][]byte, error) {
        if addr == "" {
            // allow override via env for convenience
            if v := os.Getenv("SDUMBO_ACS_ADDR"); v != "" {
                addr = v
            } else {
                return nil, errors.New("ExternalSDumboACS: empty addr and SDUMBO_ACS_ADDR not set")
            }
        }
        d := net.Dialer{Timeout: dialTimeout}
        conn, err := d.Dial("tcp", addr)
        if err != nil {
            return nil, fmt.Errorf("ExternalSDumboACS: dial %s failed: %w", addr, err)
        }
        defer conn.Close()

        // Request: SID + optional input hex (reserved), keep simple: sid\n
        req := sid
        // attach batch size if provided via env (preferred for external ACS)
        if bv := os.Getenv("ACS_BATCH_SIZE"); bv != "" {
            req = sid + "|B=" + bv
        } else if len(input) > 0 {
            // fallback hint: external service may ignore
            req = sid + "|" + fmt.Sprintf("%dB", len(input))
        }
        if !strings.HasSuffix(req, "\n") {
            req += "\n"
        }
        if _, err := io.WriteString(conn, req); err != nil {
            return nil, fmt.Errorf("ExternalSDumboACS: write request failed: %w", err)
        }

        // Response protocol
        reader := bufio.NewReader(conn)
        var num uint32
        if err := binary.Read(reader, binary.BigEndian, &num); err != nil {
            return nil, fmt.Errorf("ExternalSDumboACS: read num failed: %w", err)
        }
        out := make([][]byte, 0, int(num))
        for i := 0; i < int(num); i++ {
            var ln uint32
            if err := binary.Read(reader, binary.BigEndian, &ln); err != nil {
                return nil, fmt.Errorf("ExternalSDumboACS: read len[%d] failed: %w", i, err)
            }
            if ln == 0 {
                out = append(out, []byte{})
                continue
            }
            buf := make([]byte, ln)
            if _, err := io.ReadFull(reader, buf); err != nil {
                return nil, fmt.Errorf("ExternalSDumboACS: read payload[%d] failed: %w", i, err)
            }
            out = append(out, buf)
        }
        return out, nil
    }
}


